package com.sc.nft.admin.controller;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Maps;
import com.mate.sdk.domain.Key;
import com.sc.nft.admin.request.AddEquityPropsRequest;
import com.sc.nft.admin.request.IdRequest;
import com.sc.nft.admin.request.PageAdminEquityPropsRequest;
import com.sc.nft.annotation.SysMemberLogin;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.TransferChainCollectionDTO;
import com.sc.nft.entity.vo.PageAdminEquityPropsVO;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.helper.MetaChainHepler;
import com.sc.nft.mapper.ChainCallBackLogMapper;
import com.sc.nft.mapper.UserCollectionChainLogMapper;
import com.sc.nft.service.CollectionChainInitDetailsLogService;
import com.sc.nft.service.DigitalCollectionService;
import com.sc.nft.service.UserChainInfoService;
import com.sc.nft.sup.PageResult;
import com.sc.nft.sup.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/admin/chain/reset")
@Api(tags = "后台链重置")
public class ChainResetController {

    private final UserChainInfoDao userChainInfoDao;
    private final UserInfoDao userInfoDao;
    private final MetaChainHepler metaChainHepler;
    private final DigitalCollectionDao digitalCollectionDao;
    private final DigitalCollectionService digitalCollectionService;
    public static final String DATE_FORMAT="yyyyMMdd";
    private final UserRelevanceDao userRelevanceDao;
    private final UserCollectionDao userCollectionDao;
    private final CollectionChainInitDetailsLogDao collectionChainInitDetailsLogDao;
    private final UserPerformanceDao userPerformanceDao;

    @PostMapping(value = "/resetUserAddr", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "1.给所有用户转币", notes = "给所有用户转币", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @SysMemberLogin

    public Result resetUserAddr() {
        log.info("执行开始时间:{}", DateUtil.now());
        UserChainInfo superUser = userChainInfoDao.getByUserId(1L);
        AtomicInteger count = new AtomicInteger();
        // 让你初始化快五倍 红红火火恍恍惚惚
        for (int i = 0; i < 6; i++) {
            int finalI = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    List<UserChainInfo> list = userChainInfoDao.getListByStatus(Boolean.TRUE, finalI * 20000, (finalI + 1) * 20000);
                    for (UserChainInfo userChainInfo : list) {
                        log.info("线程：{}，执行第{}个,用户Id:{}", Thread.currentThread().getId(), count.addAndGet(1), userChainInfo.getUserId());
                        //给地址转账1个代币
                        metaChainHepler.transferBalance(superUser.getUserKey(), userChainInfo.getAddress(), Convert.toBigInteger(1000000000000L));
                    }
                    log.info("线程：{} 执行结束时间:{}", Thread.currentThread().getId(), DateUtil.now());
                }
            }).start();
        }
        return Result.success();
    }


    @PostMapping(value = "/resetCollectionChainStatusAndContractStatus", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "2.重置藏品的链状态和合约状态", notes = "重置藏品的链状态和合约状态", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @SysMemberLogin
    public Result resetCollectionChainStatusAndContractStatus() {
        log.info("重置藏品的链状态和合约状态");
        log.info("执行开始时间:{}", DateUtil.now());
        Boolean aBoolean = digitalCollectionDao.resetCollectionChainStatusAndContractStatus();
        log.info("执行结束时间:{}", DateUtil.now());
        return PageResult.success(aBoolean);
    }

    @PostMapping(value = "/batckDeployNFT", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "3.批量给藏品铸造合约", notes = "藏品铸造合约", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @SysMemberLogin
    public Result deployNFT() {
        log.info("批量给藏品铸造合约");
        log.info("执行开始时间:{}", DateUtil.now());
        List<DigitalCollection> list = digitalCollectionDao.list();
        for (DigitalCollection digitalCollection : list) {
            String transactionHash = metaChainHepler.deployNFT(digitalCollection);
            Assert.isTrue(digitalCollectionDao.updateDeployTransactionHashAndContractStatusById(digitalCollection.getId(), transactionHash, CollectionContractStatusEnum.DEPLOYING), () -> new GlobalRunTimeException("藏品表更新失败!"));
        }
        log.info("执行结束时间:{}", DateUtil.now());
        return PageResult.success();
    }


    @PostMapping(value = "/generateCollectionChainLog", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "4.生成藏品上链日志", notes = "生成藏品上链日志", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @SysMemberLogin
    public Result generateCollectionChainLog() {
        log.info("生成藏品上链日志");
        log.info("执行开始时间:{}", DateUtil.now());
        List<DigitalCollection> list = digitalCollectionDao.getListByChainStatusAndContractStatus(CollectionChainStatusEnum.WAIT_CHAIN, CollectionContractStatusEnum.DEPLOY_SUCCESS);
        for (DigitalCollection collection : list) {
            digitalCollectionService.collectionInitChain(collection);
        }
        log.info("执行结束时间:{}", DateUtil.now());
        return Result.success();
    }



//    @PostMapping(value = "/metaChainMintBatch", produces = MediaType.APPLICATION_JSON_VALUE)
//    @ApiOperation(value = "5.执行藏品上链", notes = "执行藏品上链", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
//    @SysMemberLogin
//    public Result metaChainMintBatch() {
//        log.info("执行藏品上链");
//        log.info("执行开始时间:{}", DateUtil.now());
//
//        List<DigitalCollection> digitalCollections = digitalCollectionDao.getListByChainStatusAndContractStatus(CollectionChainStatusEnum.ON_THE_CHAIN,CollectionContractStatusEnum.DEPLOY_SUCCESS);
//        for (DigitalCollection digitalCollection : digitalCollections) {
//            List<CollectionChainInitDetailsLog> list = collectionChainInitDetailsLogService.metaChainInitListAndCollectionIdAndLimit(digitalCollection.getId(),UserChainLogStatusEnum.WAIT, CollectionChainDealStatusEnum.IN_CHINA,digitalCollection.getSumCount());
//            List<List<CollectionChainInitDetailsLog>> partition = ListUtil.partition(list, 150);
//            for (List<CollectionChainInitDetailsLog> collectionChainInitDetailsLogs : partition) {
//                //上链逻辑
//                userChainInfoService.mintBatch(collectionChainInitDetailsLogs);
//            }
//        }
//
//        log.info("执行结束时间:{}", DateUtil.now());
//        return Result.success();
//    }


    @PostMapping(value = "/transferNft", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "6.插入链待执行记录", notes = "执行藏品交易", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @SysMemberLogin
    public Result transferNft() {
        log.info("执行藏品交易");
        log.info("执行开始时间:{}", DateUtil.now());
        //全部藏品合约
        List<DigitalCollection> allList = digitalCollectionDao.getListByChainStatusAndContractStatus(CollectionChainStatusEnum.CHAIN_COMPLETED, CollectionContractStatusEnum.DEPLOY_SUCCESS);
        //合约地址
        HashMap<Long, String> contractAddressMap = Maps.newHashMap();
        //部署交易hash
        HashMap<Long, String> deployTransactionHashMap = Maps.newHashMap();

        String fromUserAddress = userChainInfoDao.getByUserId(1L).getAddress();

        for (DigitalCollection digitalCollection : allList) {
            contractAddressMap.put(digitalCollection.getId(), digitalCollection.getContractAddress());
            deployTransactionHashMap.put(digitalCollection.getId(), digitalCollection.getDeployTransactionHash());
        }

        long startId = 0L;
        int end = 50000;
        for (int i = 0; i < 5; i++) {
            log.info("startId:{},end:{}", startId,end);
            List<UserCollection> collectionListByIsHold = userCollectionDao.getCollectionList(startId , end);
            for (UserCollection userCollection : collectionListByIsHold) {
                CollectionChainInitDetailsLog collectionChainInitDetailsLog = collectionChainInitDetailsLogDao.getOneByTokenIdAndCollectionId(userCollection.getNumbering(), userCollection.getCollectionId());
                Assert.isTrue(ObjectUtil.isNotNull(collectionChainInitDetailsLog), () -> new GlobalRunTimeException("链上藏品交易失败,未找到对应的上链日志!!"));
                String addr = userChainInfoDao.getByUserId(userCollection.getUserId()).getAddress();
                UserCollectionChainLog userCollectionChainLog = new UserCollectionChainLog();
                userCollectionChainLog.setUserId(userCollection.getUserId());
                userCollectionChainLog.setUserCollectionId(userCollection.getId());
                userCollectionChainLog.setCollectionType(ReceivedCollectionType.RECEIVED);
                userCollectionChainLog.setType(UserChainTypeEnum.TRANSFER);
                userCollectionChainLog.setStatus(UserChainLogStatusEnum.WAIT);
                userCollectionChainLog.setCollectionId(userCollection.getCollectionId());
                userCollectionChainLog.setContractAddress(contractAddressMap.get(userCollection.getCollectionId()));
                userCollectionChainLog.setDeployTransactionHash(deployTransactionHashMap.get(userCollection.getCollectionId()));
                userCollectionChainLog.setProductId(collectionChainInitDetailsLog.getCollectionUuid());
                userCollectionChainLog.setAddress(addr);
                userCollectionChainLog.setTokenId(collectionChainInitDetailsLog.getTokenId());
                userCollectionChainLog.setFromUserId(1l);
                userCollectionChainLog.setFromUserCollectionId(0l);
                userCollectionChainLog.setFromUserAddress(fromUserAddress);
                userCollectionChainLog.setToUserId(userCollection.getUserId());
                userCollectionChainLog.setToUserCollectionId(userCollection.getId());
                userCollectionChainLog.setToUserAddress(addr);
                userCollectionChainLog.setCollectionChainId(collectionChainInitDetailsLog.getId());
                userCollectionChainLog.insert();
                Assert.isTrue(userCollectionDao.updateStatusAndChainUrlById(userCollection.getId(), ChainStatusEnum.NONE, StrUtil.EMPTY), () -> new GlobalRunTimeException(StrUtil.format("修改用户藏品状态失败,id:{}", userCollection.getId())));
                log.info("插入链待执行记录成功,用户藏品id:{}", userCollection.getId());
            }
            startId = collectionListByIsHold.stream().max(Comparator.comparingLong(UserCollection::getId)).get().getId();
        }

        log.info("执行结束时间:{}", DateUtil.now());
        return Result.success();
    }

    private final ChainCallBackLogMapper chainCallBackLogMapper;
    private final UserCollectionChainLogMapper userCollectionChainLogMapper;
    @PostMapping(value = "/initErrorData", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "初始化错误数据", notes = "初始化错误数据", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @SysMemberLogin
    public Result initErrorData() {
        List<ChainCallBackLog> chainCallBackLogs = this.chainCallBackLogMapper.initError();
        for (ChainCallBackLog chainCallBackLog : chainCallBackLogs) {
            UserCollectionChainLog failByTokenId = userCollectionChainLogMapper.getFailByTokenId(chainCallBackLog.getTokenId());
            failByTokenId.setTransactionHash(chainCallBackLog.getTransactionHash());
            failByTokenId.updateById();
        }
        return PageResult.success();
    }

    @PostMapping(value = "/transferChainCollection", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "转移链藏品", notes = "转移链藏品", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result transferChainCollection(@Valid @RequestBody TransferChainCollectionDTO dto){
        UserInfo from = userInfoDao.getOneByUserTel(dto.getFromUserTel());
        Assert.notNull(from,()->new GlobalRunTimeException("持有人手机号不正确"));
        UserChainInfo fromUserInfo = userChainInfoDao.getRegisterByUserId(from.getId());
        UserInfo to = userInfoDao.getOneByUserTel(dto.getToUserTel());
        Assert.notNull(from,()->new GlobalRunTimeException("目标人手机号不正确"));
        UserChainInfo toUserInfo = userChainInfoDao.getRegisterByUserId(to.getId());
        return Result.success();
    }

}
